#include "dev_uart.h"
#include "device_port.h"
#include <string.h>

/**
 * @brief 串口发送
 * @param pstUart 串口设备
 * @param pu8Data 待发送数据
 * @param u32Len 待发送数据长度
 * @return @see Dev_Ret_t
 */
static Dev_Ret_t
dev_uart_transmit(Dev_Uart_t *pstUart, uint8_t* pu8Data, uint32_t u32Len)
{
    // 发送数据
    uint8_t u8Ret = pstUart->HW.pfnTransmit(pu8Data, u32Len);

    // 返回执行结果
    Dev_Ret_t eRet = (1 == u8Ret) ? DEV_OK : DEV_OPS_ERR;
    return eRet;
}

/**
 * @brief 串口监控
 * @param pstDevice 设备句柄
 * @param pstUart 串口设备
 * @return @see Dev_Ret_t
 */
static Dev_Ret_t
dev_uart_monitor(Device_t* pstDevice, Dev_Uart_t* pstUart)
{
    // 变量初始化
    uint32_t u32Length      = 0;
    uint32_t u32OldLength   = 0;
    uint32_t u32TimeOut     = 0;

    // 多次循环判断数据是否接收完成
    while(1)
    {
        // 接收数据
        u32OldLength = pstUart->HW.pfnReceive(pstUart->SW.pu8Data, pstUart->SW.u32Len);
        
        // 超时计数器加
        u32TimeOut++;

        // 长度判断
        if(u32OldLength > 0 && u32Length != u32OldLength) 
        {
            // 更新长度
            u32Length = u32OldLength;

            // 重新等待
            u32TimeOut = 0;
        }

        // 超时判断
        if(u32TimeOut > pstUart->SW.u32TimeOut) 
        {
            break;
        }

        // 延时判断
        DEV_DELAY_MS(1);
    }
    
    // 长度是否符合要求
    if(u32Length < 1) 
    {
        return DEV_DATA_NULL;
    };

    // 长度是否溢出
    if(u32Length >= pstUart->SW.u32Len)
    {
        return DEV_DATA_OVERFLOW;
    }

    // 计算缓存位置
    pstUart->SW.u32Tail = pstUart->SW.u32Len - u32Length;

    // 判断是否接收完成
    if(pstUart->SW.u32Tail != pstUart->SW.u32Head)
    {
        // 更新索引
        pstUart->SW.u32Index = u32Length;

        // 串口数据接收完成事件发送
        DEV_EMIT_EVENT(pstDevice, UART_EVT_DATA_READY);
        return DEV_OK;
    }
    
    // UART执行成功
    return DEV_OK;
}

/**
 * @brief 串口接收
 * @param pstUart 串口设备
 * @param pu8Data 接收缓存
 * @param pu32Len 接收长度
 * @return @see Dev_Ret_t
 */
static Dev_Ret_t
dev_uart_receive(Dev_Uart_t *pstUart, uint8_t* pu8Data, uint32_t* pu32Len)
{
    // 接收长度
    uint32_t u32Count = 0;

    // 计算接收长度并拷贝到目标地址
    if(pstUart->SW.u32Tail > pstUart->SW.u32Head)
    {
        // 计算长度
        u32Count = pstUart->SW.u32Tail - pstUart->SW.u32Head;

        // 拷贝数据
        memcpy(pu8Data,pstUart->SW.pu8Data+pstUart->SW.u32Head,u32Count);
    }
    else
    {
        // 计算长度
        u32Count = ( pstUart->SW.u32Len - pstUart->SW.u32Head) + pstUart->SW.u32Tail;

        // 跨区段拷贝数据
        memcpy(pu8Data,pstUart->SW.pu8Data+pstUart->SW.u32Head, 
            pstUart->SW.u32Len - pstUart->SW.u32Head);

        memcpy(pu8Data +  pstUart->SW.u32Len - pstUart->SW.u32Head,
            pstUart->SW.pu8Data,pstUart->SW.u32Tail);
    }

    // 计算新的头位置
    pstUart->SW.u32Head = pstUart->SW.u32Tail;

    // 返回接收长度
    *pu32Len = u32Count;
    
    // 执行成功
    return DEV_OK;
}

/**
 * @brief 串口设备控制函数
 * @param pstDevice 设备句柄
 * @param u8Cmd 命令
 * @param pvArg 参数
 * @return @see Dev_Ret_t
 */
Dev_Ret_t
dev_uart_ioctl(Device_t *pstDevice, uint8_t u8Cmd, void *pvArg)
{
    // 转换为Dev_Input_t结构体
    Dev_Uart_t *pstUart = GET_CONTEXT(pstDevice, Dev_Uart_t);

    // 接口检查
    if(NULL == pstUart->HW.pfnTransmit || NULL == pstUart->HW.pfnReceive) 
    {
        return DEV_INTERFACE_NULL;
    }

    // 缓存检查
    if(NULL == pstUart->SW.pu8Data || 0 == pstUart->SW.u32Len) 
    {
        return DEV_BUF_NULL;
    };

    // 非监控模式下参数不能为空
    if(u8Cmd != UART_CMD_MONITOR && NULL == pvArg)
    {
        return DEV_ARG_NULL;
    }

    // 执行命令
    switch(u8Cmd)
    {
        case UART_CMD_MONITOR:
        {
            // 监控串口
            return dev_uart_monitor(pstDevice, pstUart);
        }

        case UART_CMD_TRANSMIT:
        {
            // 转换为Dev_Uart_Data_t结构体
            Dev_Uart_Data_t *pstData = (Dev_Uart_Data_t*)pvArg;

            // 输入参数检查
            if(NULL == pstData->pu8Data) 
            {
                return DEV_ARG_ERR;
            };

            // 发送数据
            return dev_uart_transmit(pstUart, pstData->pu8Data, pstData->u32Len);
        }

        case UART_CMD_RECEIVE:
        {
            // 转换为Dev_Uart_Data_t结构体
            Dev_Uart_Data_t *pstData = (Dev_Uart_Data_t*)pvArg;
            
            // 输入参数检查
            if(NULL == pstData->pu8Data) 
            {
                return DEV_ARG_ERR;
            };

            // 接收数据
            return dev_uart_receive(pstUart, pstData->pu8Data, &pstData->u32Len);
        }

        default:
        {
            // 未知命令
            return DEV_UNKNOWN_IOCTL;
        }
    }
}
